#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <math.h>

#include "vision/list.h"
#include "vision/config.h"
#include "hi_common.h"
#include "hi_comm_sys.h"
#include "hi_comm_svp.h"
#include "sample_comm.h"
#include "sample_comm_svp.h"
#include "sample_comm_nnie.h"
#include "sample_nnie_main.h"
#include "sample_svp_nnie_software.h"
#include "sample_comm_ive.h"
#include "vision/ssd_priorbox.h"

typedef struct ssd_parameters
{
	SAMPLE_SVP_NNIE_PARAM_S *s_stDetNnieParam;
	SAMPLE_SVP_NNIE_MODEL_S *s_stDetModel;
	
	float cls_threshold;
	float nms_thresholds;
}ssd_para;

static HI_BOOL s_bNnieStopSignal = HI_FALSE;
#if 0
HI_U32 retina_write_file(const void *face_images, int data_type){
	HI_S32 s32Ret = HI_SUCCESS;
	IVE_IMAGE_S input_yvu420sp = {0};
	//HI_U32 frame_size = 0;
	//HI_U64 *frame_VirAddr = NULL;
	if (data_type == 1){ // 输入的是数组首地址
		IVE_DST_DATA_S face_image = ((IVE_DST_DATA_S *)face_images)[0];
		HI_U32 u32Align = DEFAULT_ALIGN;
		HI_U32 u32BitWidth = 8;
		HI_U32 u32Width = face_image.u32Width; 
		HI_U32 u32Height = face_image.u32Height;
		HI_U32 u32MainStride = ALIGN_UP((u32Width * u32BitWidth + 7) >> 3, u32Align);
		HI_U32 u32AlignHeight = ALIGN_UP(u32Height, 2);
		HI_U32 u32YSize = u32MainStride * u32AlignHeight;
		
		input_yvu420sp.au64PhyAddr[0] = face_image.u64PhyAddr;
		input_yvu420sp.au64VirAddr[0] = face_image.u64VirAddr;
		input_yvu420sp.au64VirAddr[1] = face_image.u64VirAddr + u32YSize;
		input_yvu420sp.au32Stride[0] = u32MainStride;
		input_yvu420sp.au32Stride[1] = u32MainStride;
		input_yvu420sp.u32Width = face_image.u32Width;
		input_yvu420sp.u32Height = face_image.u32Height;
		input_yvu420sp.enType = IVE_IMAGE_TYPE_YUV420SP;

		printf("face_image->u64VirAddr[0] = %#llx\n", face_image.u64VirAddr);
		printf("face_image->u64PhyAddr[0] = %#llx\n", face_image.u64PhyAddr);
	}else if (data_type == 2){ // 输入的单个结构体指针
		VIDEO_FRAME_INFO_S *face_image = (VIDEO_FRAME_INFO_S *)face_images;
		
		input_yvu420sp.au64PhyAddr[0] = face_image->stVFrame.u64PhyAddr[0];
		input_yvu420sp.au64VirAddr[0] = face_image->stVFrame.u64VirAddr[0];
		input_yvu420sp.au64VirAddr[1] = face_image->stVFrame.u64VirAddr[1];
		
		input_yvu420sp.au32Stride[0] = face_image->stVFrame.u32Stride[0];
		input_yvu420sp.au32Stride[1] = face_image->stVFrame.u32Stride[1];
		input_yvu420sp.u32Width = face_image->stVFrame.u32Width;
		input_yvu420sp.u32Height = face_image->stVFrame.u32Height;
		input_yvu420sp.enType = IVE_IMAGE_TYPE_YUV420SP;
		
		printf("face_image->stVFrame.u64VirAddr[0] = %#llx\n", input_yvu420sp.au64VirAddr[0]);
		printf("face_image->stVFrame.u64PhyAddr[0] = %#llx\n", input_yvu420sp.au64PhyAddr[0]);
	}else{
		printf("The second parameter is wrong !\n");
		return 1;
	}
	
	HI_CHAR pchSrcFile_name[50] = {0};
	sprintf(pchSrcFile_name,"./yvu_image/%dx%d_yvu420sp.yuv", input_yvu420sp.u32Width, input_yvu420sp.u32Height);
	printf("pchSrcFile_name = %s\n", pchSrcFile_name);
	
	FILE *yvu420sp = fopen(pchSrcFile_name, "wb");
	if (yvu420sp == NULL){
		printf("Open yvu420sp file failed \n");
		IVE_CLOSE_FILE(yvu420sp);
		return 1;
	}
	
	s32Ret = SAMPLE_COMM_IVE_WriteFile(&input_yvu420sp, yvu420sp);
    SAMPLE_CHECK_EXPR_RET(HI_SUCCESS != s32Ret,s32Ret,"Error,Write dst file failed!\n");
	
	IVE_CLOSE_FILE(yvu420sp);
	//HI_MPI_SYS_Munmap((HI_VOID*)frame_VirAddr, frame_size);
	return s32Ret;
}								
#endif
HI_S32 SSD_FillRect(VIDEO_FRAME_INFO_S *pstFrmInfo, HI_U32 u32Color, Node *predbbox, HI_U32 width, HI_U32 height)	
{
    HI_S32 s32Ret = HI_SUCCESS;
    
    VGS_HANDLE VgsHandle = -1;
    VGS_TASK_ATTR_S stVgsTask;
    VGS_ADD_COVER_S stVgsAddCover;
    
    s32Ret = HI_MPI_VGS_BeginJob(&VgsHandle); // 启动一个job
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_PRT("Vgs begin job fail,Error(%#x)\n", s32Ret);
        return s32Ret;
    }
	
    memcpy(&stVgsTask.stImgIn, pstFrmInfo, sizeof(VIDEO_FRAME_INFO_S));
    memcpy(&stVgsTask.stImgOut, pstFrmInfo, sizeof(VIDEO_FRAME_INFO_S));

    stVgsAddCover.enCoverType = COVER_QUAD_RANGLE;
    stVgsAddCover.u32Color = u32Color;
    stVgsAddCover.stQuadRangle.bSolid = HI_FALSE;
    stVgsAddCover.stQuadRangle.u32Thick = 2;

	POINT_S bbox_coordinate[4] = {0};
	Node *data_node = predbbox->next;
    while(data_node != NULL)
    {
    	bbox_coordinate[0].s32X = (int)(data_node->bbox.bbox_x_left * width); // width 是原图尺寸，此处是1920，不是300
		bbox_coordinate[0].s32Y = (int)(data_node->bbox.bbox_y_left * height); // width 是原图尺寸，此处是1080，不是300

		bbox_coordinate[1].s32X = (int)(data_node->bbox.bbox_x_right * width); // ssd返回的是个归一的坐标值，获得真实坐标需要做映射
		bbox_coordinate[1].s32Y = (int)(data_node->bbox.bbox_y_left * height); // 所以要乘上原图宽高
		
		bbox_coordinate[2].s32X = (int)(data_node->bbox.bbox_x_right * width);
		bbox_coordinate[2].s32Y = (int)(data_node->bbox.bbox_y_right * height);
		
		bbox_coordinate[3].s32X = (int)(data_node->bbox.bbox_x_left * width);
		bbox_coordinate[3].s32Y = (int)(data_node->bbox.bbox_y_right * height);

		for(int i = 0; i < 4; i++){
			bbox_coordinate[i].s32X = SSD_ALIGN_UP(bbox_coordinate[i].s32X, 2); // 海思要像素2对齐
			bbox_coordinate[i].s32Y = SSD_ALIGN_UP(bbox_coordinate[i].s32Y, 2);
			bbox_coordinate[i].s32X = coordinate_clip_int(-2686, 2686, bbox_coordinate[i].s32X); // 裁剪，不然会报错
			bbox_coordinate[i].s32Y = coordinate_clip_int(-2686, 2686, bbox_coordinate[i].s32Y);
		}
		
        memcpy(stVgsAddCover.stQuadRangle.stPoint, bbox_coordinate, sizeof(POINT_S)*4); // astPoint是一个结构体数组，储存着Bbox坐标
        data_node = data_node->next;
        s32Ret = HI_MPI_VGS_AddCoverTask(VgsHandle, &stVgsTask, &stVgsAddCover); // 往一个已经启动的job里添加打COVER task
		if (s32Ret != HI_SUCCESS)
        {
            SAMPLE_PRT("Face bbox HI_MPI_VGS_AddCoverTask fail,Error(%#x)\n", s32Ret);
            HI_MPI_VGS_CancelJob(VgsHandle); // 取消一个job
            return s32Ret;
        }	
    }
	
    s32Ret = HI_MPI_VGS_EndJob(VgsHandle);
	
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_PRT("HI_MPI_VGS_EndJob fail,Error(%#x)\n", s32Ret);
        HI_MPI_VGS_CancelJob(VgsHandle);
        return s32Ret;
    }

    return s32Ret;

}

static HI_S32 SSD_Data_Process(SAMPLE_SVP_NNIE_PARAM_S *pstParam, VIDEO_FRAME_INFO_S* pstExtFrmInfo, 
SAMPLE_SVP_NNIE_MODEL_S *s_stDetModel, float cls_threshold, float nms_threshold, PriorBox *priorbox, Node *predbbox_head_node)
{
    HI_S32 s32Ret = HI_FAILURE;
    SAMPLE_SVP_NNIE_INPUT_DATA_INDEX_S stInputDataIdx = {0};

    stInputDataIdx.u32SegIdx = 0;
    stInputDataIdx.u32NodeIdx = 0;
    /*SP420*/
    pstParam->astSegData[stInputDataIdx.u32SegIdx].astSrc[stInputDataIdx.u32NodeIdx].u64VirAddr = pstExtFrmInfo->stVFrame.u64VirAddr[0];
    pstParam->astSegData[stInputDataIdx.u32SegIdx].astSrc[stInputDataIdx.u32NodeIdx].u64PhyAddr = pstExtFrmInfo->stVFrame.u64PhyAddr[0];
    pstParam->astSegData[stInputDataIdx.u32SegIdx].astSrc[stInputDataIdx.u32NodeIdx].u32Stride  = pstExtFrmInfo->stVFrame.u32Stride[0];
    
    SAMPLE_SVP_NNIE_PROCESS_SEG_INDEX_S stProcSegIdx = {0};
    
    stInputDataIdx.u32SegIdx = 0;
    stInputDataIdx.u32NodeIdx = 0;
	
    /*NNIE process 0-th seg*/
    stProcSegIdx.u32SegIdx = 0;
    s32Ret = SAMPLE_SVP_NNIE_Forward(pstParam, &stInputDataIdx, &stProcSegIdx, HI_TRUE); // 帧数据送入nnie做前向推理
    SAMPLE_SVP_CHECK_EXPR_RET(HI_SUCCESS != s32Ret,s32Ret,SAMPLE_SVP_ERR_LEVEL_ERROR,
        "Error,SAMPLE_SVP_NNIE_Forward failed!\n");
	
	
	get_pred_bbox(pstParam, priorbox, predbbox_head_node, cls_threshold); // 置信度过滤 
	
	if (predbbox_head_node->next == NULL){
		
		return 0;
	}
	
	pred_bbox_sort(predbbox_head_node); // 置信度排序，下面nms需要，降序
	
	pred_bbox_nms(predbbox_head_node, nms_threshold); // nms操作
	
    return s32Ret;
CNN_FAIL_1:
    /*Remove TskBuf*/
    SAMPLE_SVP_TRACE_INFO("Why1 \n");
	s32Ret = HI_MPI_SVP_NNIE_RemoveTskBuf(&((*pstParam).astForwardCtrl[0].stTskBuf));
    SAMPLE_SVP_CHECK_EXPR_GOTO(HI_SUCCESS != s32Ret,CNN_FAIL_0,SAMPLE_SVP_ERR_LEVEL_ERROR,
        "Error,HI_MPI_SVP_NNIE_RemoveTskBuf failed!\n");

CNN_FAIL_0:
    SAMPLE_SVP_TRACE_INFO("Why2 \n");
	SAMPLE_SVP_NNIE_Cnn_Deinit(pstParam, s_stDetModel);
    SAMPLE_COMM_SVP_CheckSysExit();
    return s32Ret;

}


/******************************************************************************
* function : retina vi to vo thread entry
******************************************************************************/
static HI_VOID* SSD_ViToVo(HI_VOID* pArgs)
{
	HI_S32 s32Ret;
	//SAMPLE_SVP_NNIE_PARAM_S *pstParam;
	
	VIDEO_FRAME_INFO_S stBaseFrmInfo;
	VIDEO_FRAME_INFO_S stExtFrmInfo;
	HI_S32 s32MilliSec = 20000;
	VO_LAYER voLayer = 0;
	VO_CHN voChn = 0;
	HI_S32 s32VpssGrp = 0;
	HI_S32 as32VpssChn[] = {VPSS_CHN0, VPSS_CHN1};
	SAMPLE_SVP_NNIE_PARAM_S *s_stDetNnieParam = ((ssd_para *)pArgs)->s_stDetNnieParam;
	SAMPLE_SVP_NNIE_MODEL_S *s_stDetModel = ((ssd_para *)pArgs)->s_stDetModel;
	
	float cls_thresholds = ((ssd_para *)pArgs)->cls_threshold;
	float nms_threshold = ((ssd_para *)pArgs)->nms_thresholds;
	
	PriorBox *priorbox = (PriorBox *)malloc(sizeof(PriorBox) * PriorBox_Num);
	memset(priorbox, 0, sizeof(PriorBox) * PriorBox_Num);
	s32Ret = priorbox_init(priorbox); // 先验框初始化，返回储存9690个先验框的数组首地址
	
	Node *predbbox_head_node = NULL;
	
	while (HI_FALSE == s_bNnieStopSignal) // 开始循环取数据推理
	{
		
		s32Ret = HI_MPI_VPSS_GetChnFrame(s32VpssGrp, as32VpssChn[1], &stExtFrmInfo, s32MilliSec); // 扩展通道取一帧图
		if(HI_SUCCESS != s32Ret)
		{
			SAMPLE_PRT("Error(%#x),HI_MPI_VPSS_GetChnFrame failed, VPSS_GRP(%d), VPSS_CHN(%d)!\n",
				s32Ret,s32VpssGrp, as32VpssChn[1]);
			continue;
		}

		s32Ret = HI_MPI_VPSS_GetChnFrame(s32VpssGrp, as32VpssChn[0], &stBaseFrmInfo, s32MilliSec);
		SAMPLE_CHECK_EXPR_GOTO(HI_SUCCESS!=s32Ret, EXT_RELEASE,
			"Error(%#x),HI_MPI_VPSS_GetChnFrame failed, VPSS_GRP(%d), VPSS_CHN(%d)!\n",
			s32Ret,s32VpssGrp, as32VpssChn[0]);

		predbbox_head_node = (Node *)malloc(sizeof(Node)); // 定义链表头结点，下文储存bbox坐标
		memset(predbbox_head_node, 0, sizeof(Node));
		predbbox_head_node->next = NULL;
		// 后处理，置信度阈值过滤及nms
		s32Ret = SSD_Data_Process(s_stDetNnieParam, &stExtFrmInfo, s_stDetModel, cls_thresholds, nms_threshold, priorbox, 
			predbbox_head_node);
		
		SAMPLE_CHECK_EXPR_GOTO(HI_SUCCESS!=s32Ret, BASE_RELEASE, "Error(%#x),SSD_ViToVo failed!\n", s32Ret);
		
		if (predbbox_head_node->next != NULL){ // 如果有bbox数据，画图
			//Draw rect
			s32Ret = SSD_FillRect(&stBaseFrmInfo, 0x0000FF00, predbbox_head_node, stBaseFrmInfo.stVFrame.u32Width, 
			stBaseFrmInfo.stVFrame.u32Height);
			
			SAMPLE_CHECK_EXPR_GOTO(HI_SUCCESS!=s32Ret, BASE_RELEASE, "SSD_FillRect failed, Error(%#x)!\n", s32Ret);
			
		}
		
		free_bbox(predbbox_head_node); // 释放链表内存			
		
		s32Ret = HI_MPI_VO_SendFrame(voLayer, voChn, &stBaseFrmInfo, s32MilliSec);
		SAMPLE_CHECK_EXPR_GOTO(HI_SUCCESS!=s32Ret, BASE_RELEASE, "HI_MPI_VO_SendFrame failed, Error(%#x)!\n", s32Ret);
		
		BASE_RELEASE:
			s32Ret = HI_MPI_VPSS_ReleaseChnFrame(s32VpssGrp,as32VpssChn[0], &stBaseFrmInfo);
			if (HI_SUCCESS != s32Ret)
			{
				SAMPLE_PRT("Error(%#x),HI_MPI_VPSS_ReleaseChnFrame failed,Grp(%d) chn(%d)!\n",
					s32Ret,s32VpssGrp,as32VpssChn[0]);
			}

		EXT_RELEASE:
			s32Ret = HI_MPI_VPSS_ReleaseChnFrame(s32VpssGrp,as32VpssChn[1], &stExtFrmInfo);
			if (HI_SUCCESS != s32Ret)
			{
				SAMPLE_PRT("Error(%#x),HI_MPI_VPSS_ReleaseChnFrame failed,Grp(%d) chn(%d)!\n",
					s32Ret,s32VpssGrp,as32VpssChn[1]);
			}
			
	}
	
	free(priorbox);
	return HI_NULL;
}



void main(int argc, char *argv[])
{
	float cls_thresholds = 0.45f; // 阈值不要太高，不然没东西的，pytorch版本也就 0.3 的阈值
	float nms_thresholds = 0.4f;
	if (argc > 1){
		int int_cls_thre = atoi(argv[1]);
		int int_nms_thre = atoi(argv[2]);
		cls_thresholds = int_cls_thre / 100.0f;
		nms_thresholds = int_nms_thre / 100.0f;
	}
	printf("cls_thresholds = %f\tnms_thresholds = %f\n", cls_thresholds, nms_thresholds);
	HI_CHAR *pcModelName = "./pedestrain_detec_yvu2bgr.wk";
	printf("WK model_1 path = %s\n",pcModelName);
	PIC_SIZE_E enSize = PIC_300x300;
	
	static pthread_t s_hNnieThread = 0;
	static SAMPLE_VI_CONFIG_S s_stViConfig = {0};
	static SAMPLE_SVP_NNIE_MODEL_S s_stRfcnModel = {0};
	static SAMPLE_IVE_SWITCH_S s_stRfcnSwitch = {HI_FALSE,HI_FALSE};
	
	static SAMPLE_SVP_NNIE_MODEL_S s_stDetModel = {0};
	
    SAMPLE_SVP_NNIE_CFG_S   stNnieCfg = {0};
	
    SIZE_S stSize;
	
    HI_S32 s32Ret = HI_SUCCESS;
    HI_CHAR acThreadName[16] = {0};

    memset(&s_stRfcnModel,0,sizeof(s_stRfcnModel));
 
    /******************************************
     step 1: start vi vpss vo
     ******************************************/
    s_stRfcnSwitch.bVenc = HI_FALSE;
    s_stRfcnSwitch.bVo   = HI_TRUE;
    s32Ret = SAMPLE_COMM_IVE_StartViVpssVencVo(&s_stViConfig,&s_stRfcnSwitch,&enSize);
    SAMPLE_CHECK_EXPR_GOTO(HI_SUCCESS != s32Ret, END_RFCN_0,
        "Error(%#x),SAMPLE_COMM_IVE_StartViVpssVencVo failed!\n", s32Ret);

    s32Ret = SAMPLE_COMM_SYS_GetPicSize(enSize, &stSize); // modify size here; set w=640 h=640 
    SAMPLE_CHECK_EXPR_GOTO(HI_SUCCESS != s32Ret, END_RFCN_0,
        "Error(%#x),SAMPLE_COMM_SYS_GetPicSize_1 failed!\n", s32Ret);
	
	printf("L345 the size of image_1 send to nnie: %dx%d\n",stSize.u32Height,stSize.u32Width);
	
	/******************************************
     step 2: init
     ******************************************/
    /*Set configuration parameter*/
    HI_U32 u32PicNum = 1;
    /*Set configuration parameter*/
    stNnieCfg.u32MaxInputNum = u32PicNum; //max input image num in each batch ; stNnieCfg = {0}
    stNnieCfg.u32MaxRoiNum = 0;
    stNnieCfg.aenNnieCoreId[0] = SVP_NNIE_ID_0;//set NNIE core
	
	static SAMPLE_SVP_NNIE_PARAM_S s_stDetNnieParam = {0};
	
	ssd_para SSD_ViToVo_para = {0};
	SSD_ViToVo_para.s_stDetNnieParam = &s_stDetNnieParam;
	SSD_ViToVo_para.s_stDetModel = &s_stDetModel;
	
    /*Sys init*/
    //SAMPLE_COMM_SVP_CheckSysInit(); // 初始化系统，因为在SAMPLE_COMM_IVE_StartViVpssVencVo中已经初始化了，所以注释掉
#if 1
    /*CNN Load model*/
    SAMPLE_SVP_TRACE_INFO("face_detect_model Load model!\n");
    s32Ret = SAMPLE_COMM_SVP_NNIE_LoadModel(pcModelName,&s_stDetModel); // sample_comm_nnie.c 文件下定义 ；全局变量 ：结构体 s_stDetModel 初始全为0，里面储存了模型网络结构的指针 。
    SAMPLE_SVP_CHECK_EXPR_GOTO(HI_SUCCESS != s32Ret,CNN_FAIL_0,SAMPLE_SVP_ERR_LEVEL_ERROR,
        "Error,SAMPLE_COMM_SVP_NNIE_LoadModel_1 failed!\n");
    
    SSD_ViToVo_para.cls_threshold = cls_thresholds;
	SSD_ViToVo_para.nms_thresholds = nms_thresholds;
		
    /*CNN parameter initialization*/
    /*Cnn software parameters are set in SAMPLE_SVP_NNIE_Cnn_SoftwareParaInit,
     if user has changed net struct, please make sure the parameter settings in
     SAMPLE_SVP_NNIE_Cnn_SoftwareParaInit function are correct*/
    SAMPLE_SVP_TRACE_INFO("pedestrain_detec_model parameter initialization!\n");
    s_stDetNnieParam.pstModel = &s_stDetModel.stModel; // 网络模型结构体 stModel 。
    s32Ret = SAMPLE_SVP_NNIE_Cnn_ParamInit(&stNnieCfg,&s_stDetNnieParam); // 初始化 NNIE 硬件层参数
    SAMPLE_SVP_CHECK_EXPR_GOTO(HI_SUCCESS != s32Ret,CNN_FAIL_0,SAMPLE_SVP_ERR_LEVEL_ERROR,
        "Error,SAMPLE_SVP_NNIE_Cnn_ParamInit_1 failed!\n");
    SAMPLE_SVP_TRACE_INFO("pedestrain_detec_model NNIE AddTskBuf!\n");
    /*record tskBuf*/
    s32Ret = HI_MPI_SVP_NNIE_AddTskBuf(&(s_stDetNnieParam.astForwardCtrl[0].stTskBuf)); // 记录 TskBuf 地址信息 ,用于减少内核态内存映射次数 ,提升效率 。
    SAMPLE_SVP_CHECK_EXPR_GOTO(HI_SUCCESS != s32Ret,CNN_FAIL_0,SAMPLE_SVP_ERR_LEVEL_ERROR,
        "Error,HI_MPI_SVP_NNIE_AddTskBuf_1 failed!\n");
    SAMPLE_SVP_TRACE_INFO("pedestrain_detec_model NNIE AddTskBuf end!\n");
	
#endif	
	/******************************************
		  step 3: Create work thread
	******************************************/
	//printf("Create work thread\n");
	snprintf(acThreadName, 16, "NNIE_ViToVo");
	prctl(PR_SET_NAME, (unsigned long)acThreadName, 0,0,0);
	pthread_create(&s_hNnieThread, 0, SSD_ViToVo, (HI_VOID*)(&SSD_ViToVo_para));

	SAMPLE_PAUSE();

	s_bNnieStopSignal = HI_TRUE;
	pthread_join(s_hNnieThread, HI_NULL);
	s_hNnieThread = 0;
CNN_FAIL_1:
	/*Remove TskBuf*/
	s32Ret = HI_MPI_SVP_NNIE_RemoveTskBuf(&(s_stDetNnieParam.astForwardCtrl[0].stTskBuf)); // 如果 TskBuf 不再使用，需要将记录的 TskBuf 地址信息从链表中移除,必须与 HI_MPI_SVP_NNIE_AddTskBuf 成对匹配使用 。
	SAMPLE_SVP_CHECK_EXPR_GOTO(HI_SUCCESS != s32Ret,CNN_FAIL_0,SAMPLE_SVP_ERR_LEVEL_ERROR,
		"Error,HI_MPI_SVP_NNIE_RemoveTskBuf failed!\n");

CNN_FAIL_0:
	SAMPLE_SVP_TRACE_INFO("Why_1 \n");
	SAMPLE_SVP_NNIE_Cnn_Deinit(&s_stDetNnieParam, &s_stDetModel);
	SAMPLE_COMM_SVP_CheckSysExit();

CNN_FAIL_3:
	/*Remove TskBuf*/
	//2Ret = HI_MPI_SVP_NNIE_RemoveTskBuf(&(s_stExtNnieParam.astForwardCtrl[0].stTskBuf));
	SAMPLE_SVP_CHECK_EXPR_GOTO(HI_SUCCESS != s32Ret,CNN_FAIL_0,SAMPLE_SVP_ERR_LEVEL_ERROR,
		"Error,HI_MPI_SVP_NNIE_RemoveTskBuf failed!\n");

CNN_FAIL_2:
	SAMPLE_SVP_TRACE_INFO("Why_2 \n");
	//MPLE_SVP_NNIE_Cnn_Deinit(&s_stExtNnieParam,&s_stExtModel);
	SAMPLE_SVP_NNIE_Cnn_Deinit(&s_stDetNnieParam, &s_stDetModel);
	SAMPLE_COMM_SVP_CheckSysExit();

//END_RFCN_1:
	
	//SAMPLE_SVP_NNIE_Rfcn_Deinit(&s_stRfcnNnieParam,&s_stRfcnSoftwareParam,&s_stRfcnModel);
END_RFCN_0:
	SAMPLE_COMM_IVE_StopViVpssVencVo(&s_stViConfig,&s_stRfcnSwitch);
	return ;
	
}

